/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package carstoredb.models;

import carstoredb.models.exceptions.NonexistentEntityException;
import java.io.Serializable;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

/**
 *
 * @author wuhao
 */
public class CarJpaController implements Serializable {

	public CarJpaController(EntityManagerFactory emf) {
		this.emf = emf;
	}
	private EntityManagerFactory emf = null;

	public EntityManager getEntityManager() {
		return emf.createEntityManager();
	}

	public void create(Car car) {
		if (car.getOrderInfoCollection() == null) {
			car.setOrderInfoCollection(new ArrayList<OrderInfo>());
		}
		if (car.getStoreInfoCollection() == null) {
			car.setStoreInfoCollection(new ArrayList<StoreInfo>());
		}
		if (car.getUserInfoCollection() == null) {
			car.setUserInfoCollection(new ArrayList<UserInfo>());
		}
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			Collection<OrderInfo> attachedOrderInfoCollection = new ArrayList<OrderInfo>();
			for (OrderInfo orderInfoCollectionOrderInfoToAttach : car.getOrderInfoCollection()) {
				orderInfoCollectionOrderInfoToAttach = em.getReference(orderInfoCollectionOrderInfoToAttach.getClass(), orderInfoCollectionOrderInfoToAttach.getOrderId());
				attachedOrderInfoCollection.add(orderInfoCollectionOrderInfoToAttach);
			}
			car.setOrderInfoCollection(attachedOrderInfoCollection);
			Collection<StoreInfo> attachedStoreInfoCollection = new ArrayList<StoreInfo>();
			for (StoreInfo storeInfoCollectionStoreInfoToAttach : car.getStoreInfoCollection()) {
				storeInfoCollectionStoreInfoToAttach = em.getReference(storeInfoCollectionStoreInfoToAttach.getClass(), storeInfoCollectionStoreInfoToAttach.getId());
				attachedStoreInfoCollection.add(storeInfoCollectionStoreInfoToAttach);
			}
			car.setStoreInfoCollection(attachedStoreInfoCollection);
			Collection<UserInfo> attachedUserInfoCollection = new ArrayList<UserInfo>();
			for (UserInfo userInfoCollectionUserInfoToAttach : car.getUserInfoCollection()) {
				userInfoCollectionUserInfoToAttach = em.getReference(userInfoCollectionUserInfoToAttach.getClass(), userInfoCollectionUserInfoToAttach.getId());
				attachedUserInfoCollection.add(userInfoCollectionUserInfoToAttach);
			}
			car.setUserInfoCollection(attachedUserInfoCollection);
			em.persist(car);
			for (OrderInfo orderInfoCollectionOrderInfo : car.getOrderInfoCollection()) {
				Car oldCarIDOfOrderInfoCollectionOrderInfo = orderInfoCollectionOrderInfo.getCarID();
				orderInfoCollectionOrderInfo.setCarID(car);
				orderInfoCollectionOrderInfo = em.merge(orderInfoCollectionOrderInfo);
				if (oldCarIDOfOrderInfoCollectionOrderInfo != null) {
					oldCarIDOfOrderInfoCollectionOrderInfo.getOrderInfoCollection().remove(orderInfoCollectionOrderInfo);
					oldCarIDOfOrderInfoCollectionOrderInfo = em.merge(oldCarIDOfOrderInfoCollectionOrderInfo);
				}
			}
			for (StoreInfo storeInfoCollectionStoreInfo : car.getStoreInfoCollection()) {
				Car oldCarIDOfStoreInfoCollectionStoreInfo = storeInfoCollectionStoreInfo.getCarID();
				storeInfoCollectionStoreInfo.setCarID(car);
				storeInfoCollectionStoreInfo = em.merge(storeInfoCollectionStoreInfo);
				if (oldCarIDOfStoreInfoCollectionStoreInfo != null) {
					oldCarIDOfStoreInfoCollectionStoreInfo.getStoreInfoCollection().remove(storeInfoCollectionStoreInfo);
					oldCarIDOfStoreInfoCollectionStoreInfo = em.merge(oldCarIDOfStoreInfoCollectionStoreInfo);
				}
			}
			for (UserInfo userInfoCollectionUserInfo : car.getUserInfoCollection()) {
				Car oldCarIDOfUserInfoCollectionUserInfo = userInfoCollectionUserInfo.getCarID();
				userInfoCollectionUserInfo.setCarID(car);
				userInfoCollectionUserInfo = em.merge(userInfoCollectionUserInfo);
				if (oldCarIDOfUserInfoCollectionUserInfo != null) {
					oldCarIDOfUserInfoCollectionUserInfo.getUserInfoCollection().remove(userInfoCollectionUserInfo);
					oldCarIDOfUserInfoCollectionUserInfo = em.merge(oldCarIDOfUserInfoCollectionUserInfo);
				}
			}
			em.getTransaction().commit();
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public void edit(Car car) throws NonexistentEntityException, Exception {
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			Car persistentCar = em.find(Car.class, car.getId());
			Collection<OrderInfo> orderInfoCollectionOld = persistentCar.getOrderInfoCollection();
			Collection<OrderInfo> orderInfoCollectionNew = car.getOrderInfoCollection();
			Collection<StoreInfo> storeInfoCollectionOld = persistentCar.getStoreInfoCollection();
			Collection<StoreInfo> storeInfoCollectionNew = car.getStoreInfoCollection();
			Collection<UserInfo> userInfoCollectionOld = persistentCar.getUserInfoCollection();
			Collection<UserInfo> userInfoCollectionNew = car.getUserInfoCollection();
			Collection<OrderInfo> attachedOrderInfoCollectionNew = new ArrayList<OrderInfo>();
			for (OrderInfo orderInfoCollectionNewOrderInfoToAttach : orderInfoCollectionNew) {
				orderInfoCollectionNewOrderInfoToAttach = em.getReference(orderInfoCollectionNewOrderInfoToAttach.getClass(), orderInfoCollectionNewOrderInfoToAttach.getOrderId());
				attachedOrderInfoCollectionNew.add(orderInfoCollectionNewOrderInfoToAttach);
			}
			orderInfoCollectionNew = attachedOrderInfoCollectionNew;
			car.setOrderInfoCollection(orderInfoCollectionNew);
			Collection<StoreInfo> attachedStoreInfoCollectionNew = new ArrayList<StoreInfo>();
			for (StoreInfo storeInfoCollectionNewStoreInfoToAttach : storeInfoCollectionNew) {
				storeInfoCollectionNewStoreInfoToAttach = em.getReference(storeInfoCollectionNewStoreInfoToAttach.getClass(), storeInfoCollectionNewStoreInfoToAttach.getId());
				attachedStoreInfoCollectionNew.add(storeInfoCollectionNewStoreInfoToAttach);
			}
			storeInfoCollectionNew = attachedStoreInfoCollectionNew;
			car.setStoreInfoCollection(storeInfoCollectionNew);
			Collection<UserInfo> attachedUserInfoCollectionNew = new ArrayList<UserInfo>();
			for (UserInfo userInfoCollectionNewUserInfoToAttach : userInfoCollectionNew) {
				userInfoCollectionNewUserInfoToAttach = em.getReference(userInfoCollectionNewUserInfoToAttach.getClass(), userInfoCollectionNewUserInfoToAttach.getId());
				attachedUserInfoCollectionNew.add(userInfoCollectionNewUserInfoToAttach);
			}
			userInfoCollectionNew = attachedUserInfoCollectionNew;
			car.setUserInfoCollection(userInfoCollectionNew);
			car = em.merge(car);
			for (OrderInfo orderInfoCollectionOldOrderInfo : orderInfoCollectionOld) {
				if (!orderInfoCollectionNew.contains(orderInfoCollectionOldOrderInfo)) {
					orderInfoCollectionOldOrderInfo.setCarID(null);
					orderInfoCollectionOldOrderInfo = em.merge(orderInfoCollectionOldOrderInfo);
				}
			}
			for (OrderInfo orderInfoCollectionNewOrderInfo : orderInfoCollectionNew) {
				if (!orderInfoCollectionOld.contains(orderInfoCollectionNewOrderInfo)) {
					Car oldCarIDOfOrderInfoCollectionNewOrderInfo = orderInfoCollectionNewOrderInfo.getCarID();
					orderInfoCollectionNewOrderInfo.setCarID(car);
					orderInfoCollectionNewOrderInfo = em.merge(orderInfoCollectionNewOrderInfo);
					if (oldCarIDOfOrderInfoCollectionNewOrderInfo != null && !oldCarIDOfOrderInfoCollectionNewOrderInfo.equals(car)) {
						oldCarIDOfOrderInfoCollectionNewOrderInfo.getOrderInfoCollection().remove(orderInfoCollectionNewOrderInfo);
						oldCarIDOfOrderInfoCollectionNewOrderInfo = em.merge(oldCarIDOfOrderInfoCollectionNewOrderInfo);
					}
				}
			}
			for (StoreInfo storeInfoCollectionOldStoreInfo : storeInfoCollectionOld) {
				if (!storeInfoCollectionNew.contains(storeInfoCollectionOldStoreInfo)) {
					storeInfoCollectionOldStoreInfo.setCarID(null);
					storeInfoCollectionOldStoreInfo = em.merge(storeInfoCollectionOldStoreInfo);
				}
			}
			for (StoreInfo storeInfoCollectionNewStoreInfo : storeInfoCollectionNew) {
				if (!storeInfoCollectionOld.contains(storeInfoCollectionNewStoreInfo)) {
					Car oldCarIDOfStoreInfoCollectionNewStoreInfo = storeInfoCollectionNewStoreInfo.getCarID();
					storeInfoCollectionNewStoreInfo.setCarID(car);
					storeInfoCollectionNewStoreInfo = em.merge(storeInfoCollectionNewStoreInfo);
					if (oldCarIDOfStoreInfoCollectionNewStoreInfo != null && !oldCarIDOfStoreInfoCollectionNewStoreInfo.equals(car)) {
						oldCarIDOfStoreInfoCollectionNewStoreInfo.getStoreInfoCollection().remove(storeInfoCollectionNewStoreInfo);
						oldCarIDOfStoreInfoCollectionNewStoreInfo = em.merge(oldCarIDOfStoreInfoCollectionNewStoreInfo);
					}
				}
			}
			for (UserInfo userInfoCollectionOldUserInfo : userInfoCollectionOld) {
				if (!userInfoCollectionNew.contains(userInfoCollectionOldUserInfo)) {
					userInfoCollectionOldUserInfo.setCarID(null);
					userInfoCollectionOldUserInfo = em.merge(userInfoCollectionOldUserInfo);
				}
			}
			for (UserInfo userInfoCollectionNewUserInfo : userInfoCollectionNew) {
				if (!userInfoCollectionOld.contains(userInfoCollectionNewUserInfo)) {
					Car oldCarIDOfUserInfoCollectionNewUserInfo = userInfoCollectionNewUserInfo.getCarID();
					userInfoCollectionNewUserInfo.setCarID(car);
					userInfoCollectionNewUserInfo = em.merge(userInfoCollectionNewUserInfo);
					if (oldCarIDOfUserInfoCollectionNewUserInfo != null && !oldCarIDOfUserInfoCollectionNewUserInfo.equals(car)) {
						oldCarIDOfUserInfoCollectionNewUserInfo.getUserInfoCollection().remove(userInfoCollectionNewUserInfo);
						oldCarIDOfUserInfoCollectionNewUserInfo = em.merge(oldCarIDOfUserInfoCollectionNewUserInfo);
					}
				}
			}
			em.getTransaction().commit();
		} catch (Exception ex) {
			String msg = ex.getLocalizedMessage();
			if (msg == null || msg.length() == 0) {
				Integer id = car.getId();
				if (findCar(id) == null) {
					throw new NonexistentEntityException("The car with id " + id + " no longer exists.");
				}
			}
			throw ex;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public void destroy(Integer id) throws NonexistentEntityException {
		EntityManager em = null;
		try {
			em = getEntityManager();
			em.getTransaction().begin();
			Car car;
			try {
				car = em.getReference(Car.class, id);
				car.getId();
			} catch (EntityNotFoundException enfe) {
				throw new NonexistentEntityException("The car with id " + id + " no longer exists.", enfe);
			}
			Collection<OrderInfo> orderInfoCollection = car.getOrderInfoCollection();
			for (OrderInfo orderInfoCollectionOrderInfo : orderInfoCollection) {
				orderInfoCollectionOrderInfo.setCarID(null);
				orderInfoCollectionOrderInfo = em.merge(orderInfoCollectionOrderInfo);
			}
			Collection<StoreInfo> storeInfoCollection = car.getStoreInfoCollection();
			for (StoreInfo storeInfoCollectionStoreInfo : storeInfoCollection) {
				storeInfoCollectionStoreInfo.setCarID(null);
				storeInfoCollectionStoreInfo = em.merge(storeInfoCollectionStoreInfo);
			}
			Collection<UserInfo> userInfoCollection = car.getUserInfoCollection();
			for (UserInfo userInfoCollectionUserInfo : userInfoCollection) {
				userInfoCollectionUserInfo.setCarID(null);
				userInfoCollectionUserInfo = em.merge(userInfoCollectionUserInfo);
			}
			em.remove(car);
			em.getTransaction().commit();
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	public List<Car> findCarEntities() {
		return findCarEntities(true, -1, -1);
	}

	public List<Car> findCarEntities(int maxResults, int firstResult) {
		return findCarEntities(false, maxResults, firstResult);
	}

	private List<Car> findCarEntities(boolean all, int maxResults, int firstResult) {
		EntityManager em = getEntityManager();
		try {
			CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
			cq.select(cq.from(Car.class));
			Query q = em.createQuery(cq);
			if (!all) {
				q.setMaxResults(maxResults);
				q.setFirstResult(firstResult);
			}
			return q.getResultList();
		} finally {
			em.close();
		}
	}

	public Car findCar(Integer id) {
		EntityManager em = getEntityManager();
		try {
			return em.find(Car.class, id);
		} finally {
			em.close();
		}
	}

	public int getCarCount() {
		EntityManager em = getEntityManager();
		try {
			CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
			Root<Car> rt = cq.from(Car.class);
			cq.select(em.getCriteriaBuilder().count(rt));
			Query q = em.createQuery(cq);
			return ((Long) q.getSingleResult()).intValue();
		} finally {
			em.close();
		}
	}
	
}
